// 该文件中包含了service_execute()函数，该函数用于执行service
#define  _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/un.h>
#include <signal.h>
#include <sys/sysinfo.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/prctl.h>
#include <sys/stat.h>

#include "unit.h"
#include "../utils/config.h"
#include "execute.h"



/*
 * @brief 执行service
 * @param service  Service结构体
 * @param pipe_handler  处理SIGPIPE信号的函数
 * @return 成功返回子进程pid，失败返回-1
 * @note 子进程会执行service->binpath，并且会设置stdio，设置signal处理信号，并且会设置环境变量
*/
int service_execute(Service *service,void *pipe_handler){
    pid_t pid = fork();
    if (pid < 0){
        fprintf(stderr, "Failed to fork: %s\n", strerror(errno));
        // printf("[\033[3;31mfailed\033[0m] rinitd fork faild ->%d\n",pid);
        fflush(stdout);
        return -1;
    }else if (pid == 0){ //子进程
        if (setsid()<0)
        {
            exit(EXIT_FAILURE);
        }
        //设置stdio
        int nullfd=open("/dev/null",O_RDWR);
        char msg[1024];
        service->pid=getpid();
        sprintf(msg,"%s[%d]",service->binname,service->pid);
        int unix_fd=0;
        if (service->std_in!=NULL)
        {
            if (strcmp(service->std_in,"tty1")==0)
            {
                int tty=open("/dev/tty1",O_RDONLY);
                dup2(tty,STDIN_FILENO);
                close(tty);
            }else{
                dup2(nullfd,STDIN_FILENO);
            }
        }else{
            dup2(nullfd,STDIN_FILENO);
        }
        if (service->std_out!=NULL)
        {
             if (strcmp(service->std_out,"tty1")==0)
            {
                int tty=open("/dev/tty1",O_WRONLY);
                dup2(tty,STDOUT_FILENO);
                close(tty);
            }else if (strcmp(service->std_out,"journal")==0)
            {
                if ((unix_fd=fd_handle("/run/journald.socket",msg))>0)
                {
                    dup2(unix_fd,STDOUT_FILENO);
                }else{
                    unix_fd=nullfd;
                    dup2(unix_fd,STDOUT_FILENO);
                }
            }else{
                dup2(nullfd,STDIN_FILENO);
            }
        }else{
            dup2(nullfd,STDOUT_FILENO);
        }
        if (service->std_err!=NULL)
        {
            if (strcmp(service->std_err,"tty1")==0)
            {
                int tty=open("/dev/tty1",O_WRONLY);
                dup2(tty,STDERR_FILENO);
                close(tty);
            }else if (strcmp(service->std_err,"journal")==0)
            {
                dup2(unix_fd,STDERR_FILENO);   
            }   
        }else{
            dup2(nullfd,STDERR_FILENO);
        }
        if ((unix_fd > 0) && (unix_fd!=nullfd))
        {
            close(unix_fd);
        }
        close(nullfd);
        //设置signal处理信号
        signal(SIGPIPE,pipe_handler);
        //装载二进制并且执行
        if (execve(service->binpath,service->argv,service->environ)<0){
            printf("ExecErr: %s\n",strerror(errno));
            _exit(EXIT_FAILURE);
        }
        return 0;
    }else{  //父进程
        service->pid=pid;
        return pid;
    }  
}


int service_wait(Service *service,int timeout){
    int status;
    int ret=waitpid(service->pid,&status,0);
    if (ret<0){
        if (errno==ECHILD){
            return -1;
        }else{
            return -2;
        }
    }else if (ret==0){
        return -3;
    }else{
        if (WIFEXITED(status)){
            return WEXITSTATUS(status);
        }else{
            return -4;
        }
    }
}   

int service_stop(Service *service){
    if (kill(service->pid,SIGTERM)<0){
        if (errno==ESRCH) return -1;
        if (errno==EPERM) return -2;
        if (errno==ECHILD) return -3;
        if (errno==EINTR) return -4;
        if (errno==EAGAIN) return kill(service->pid,SIGKILL);
    }else{
        return 0;
    }
}

int service_start(Service *service){
    if (service->pid>0){
        return 0;
    }
    return service_execute(service,NULL);
}

int service_check(Service *service){
    if (service->pid>0){
        return 0;
    }else{
        return -1;
    }
}

int service_restart(Service *service){
    if (service->pid>0){
        service_stop(service);
    }
    return service_start(service);
}

int service_reload(Service *service){
    if (service->pid>0){
        service_stop(service);
    }
    return service_start(service);
}

int service_status(Service *service){
    if (service->pid>0){
        return 0;
    }else{
        return -1;
    }
}

/*
 * @brief 执行target
 * @param target  target_def结构体
 * @return 成功返回0，失败返回-1    
 * @note 检查target中所有service是否执行成功，如果有失败的service或者没有就绪的service，则等待，直到所有service都执行成功或者超时
*/
int target_start(Target *target){
    // fprintf(logout,"    >>>Start target %s\n",target->meta.name);
    for (size_t i = 0; i < target->meta.taskQueueSize; i++)
    {
        switch (target->meta.taskQueue[i]->type)
        {
        case UNIT_SERVICE:
            service_start((Service*)target->meta.taskQueue[i]);
            break;
        case UNIT_TARGET:
            target_start((Target*)target->meta.taskQueue[i]);
            break;
        default:
            break;
        }
    }     
    return 0;
}
